part of '../widgets.dart';

enum VanImageStatus { loading, completed, error }

/// [Widget] 增强版的 img 标签，提供多种图片填充模式，支持图片懒加载、加载中提示、加载失败提示。
class VanImage extends StatelessWidget {
  /// props - 图片信息
  final ImageProvider image;

  /// props - 图片填充模式，等同于原生的 object-fit 属性(默认: fill)
  final BoxFit fit;

  /// props - 图片位置，等同于原生的 object-position 属性，可选值为 top right bottom left 或 string(默认: center)
  final Alignment position;

  /// props - 替代文本
  final String? alt;

  /// props - 宽度，默认单位为 px
  final double? width;

  /// props - 高度，默认单位为 px
  final double? height;

  /// props - 圆角大小，默认单位为 px(默认: 0)
  final double? radius;

  /// props - 是否显示为圆形(默认: false)
  final bool round;

  /// props - 是否将根节点设置为块级元素，默认情况下为 inline-block 元素(默认: false)
  final bool block;

  /// props - 是否开启图片懒加载，须配合 Lazyload 组件使用(默认: false)
  final bool lazyLoad;

  /// props - 是否展示图片加载失败提示(默认: true)
  final bool showError;

  /// props - 是否展示图片加载中提示(默认: true)
  final bool showLoading;

  /// props - 失败时提示的图标名称或图片链接，等同于 Icon 组件的 name 属性(默认: photo-fail)
  final String errorIcon;

  /// props - 加载时提示的图标名称或图片链接，等同于 Icon 组件的 name 属性(默认: photo)
  final String loadingIcon;

  /// props - 加载图标和失败图标的大小(默认: 32px)
  final double? iconSize;

  /// props - 图标类名前缀，等同于 Icon 组件的 class-prefix 属性(默认: van-icon)
  final String iconPrefix;

  final VanImageStyle? style;

  /// events - 点击图片时触发
  final Function()? onClick;

  /// events - 图片加载完毕时触发
  final Function()? onLoad;

  /// events - 图片加载失败时触发
  final Function()? onError;

  /// events - 自定义图片下方的内容
  final Widget? child;

  /// events - 自定义加载中的提示内容
  final Widget? childLoading;

  /// events - 自定义加载失败时的提示内容
  final Widget? childError;

  const VanImage({
    super.key,
    required this.image,
    this.fit = BoxFit.fill,
    this.position = Alignment.center,
    this.alt,
    this.width,
    this.height,
    this.radius,
    this.round = false,
    this.block = false,
    this.lazyLoad = false,
    this.showError = true,
    this.showLoading = true,
    this.errorIcon = "photo-fail",
    this.loadingIcon = "photo",
    this.iconSize,
    this.iconPrefix = kVanIconFontFamily,
    this.style,
    this.onClick,
    this.onLoad,
    this.onError,
    this.child,
    this.childLoading,
    this.childError,
  });

  VanImage.network(String src, {
    super.key,
    this.fit = BoxFit.fill,
    this.position = Alignment.center,
    this.alt,
    this.width,
    this.height,
    this.radius,
    this.round = false,
    this.block = false,
    this.lazyLoad = false,
    this.showError = true,
    this.showLoading = true,
    this.errorIcon = "photo-fail",
    this.loadingIcon = "photo",
    this.iconSize,
    this.iconPrefix = kVanIconFontFamily,
    this.style,
    this.onClick,
    this.onLoad,
    this.onError,
    this.child,
    this.childLoading,
    this.childError,
    double scale = 1.0,
    Map<String, String>? headers,
    int? cacheWidth,
    int? cacheHeight,
  })  : image = ResizeImage.resizeIfNeeded(cacheWidth, cacheHeight, NetworkImage(src, scale: scale, headers: headers)),
        assert(cacheWidth == null || cacheWidth > 0),
        assert(cacheHeight == null || cacheHeight > 0);

  VanImageStyle getComputedStyle(BuildContext context) {
    if (style?.isNonNull == true) return style!;
    double? width = this.width ?? style?.width;
    double? height = this.height ?? style?.height;
    Color? placeholderTextColor = style?.placeholderTextColor;
    double? placeholderFontSize = style?.placeholderFontSize;
    VanBgColor? placeholderBackground = style?.placeholderBackground;
    double? loadingIconSize = style?.loadingIconSize;
    Color? loadingIconColor = style?.loadingIconColor;
    double? errorIconSize = style?.errorIconSize;
    Color? errorIconColor = style?.errorIconColor;

    placeholderTextColor ??= kVanImagePlaceholderTextColor.toColor(context);
    placeholderFontSize ??= kVanImagePlaceholderFontSize.toDouble(context);
    placeholderBackground ??= kVanImagePlaceholderBackground.toBgColor(context);
    loadingIconSize ??= kVanImageLoadingIconSize.toDouble(context);
    loadingIconColor ??= kVanImageLoadingIconColor.toColor(context);
    errorIconSize ??= kVanImageErrorIconSize.toDouble(context);
    errorIconColor ??= kVanImageErrorIconColor.toColor(context);

    return VanImageStyle(
      width: width,
      height: height,
      placeholderTextColor: placeholderTextColor,
      placeholderFontSize: placeholderFontSize,
      placeholderBackground: placeholderBackground,
      loadingIconSize: loadingIconSize,
      loadingIconColor: loadingIconColor,
      errorIconSize: errorIconSize,
      errorIconColor: errorIconColor,
    );
  }

  @override
  Widget build(BuildContext context) {
    final style = getComputedStyle(context);

    final borderRadius = !round ? null : BorderRadius.all(Radius.elliptical(style.width!, style.height!));
    DecorationImage? decorationImage;

    VanImageStatus status = VanImageStatus.loading;
    StateSetter? setStateFn;
    final resolve = image.resolve(ImageConfiguration.empty);
    resolve.addListener(ImageStreamListener((image, synchronousCall) {
      status = VanImageStatus.completed;
      decorationImage = DecorationImage(image: this.image, alignment: position, fit: fit);
      if (setStateFn != null) setStateFn!(() {});
    }, onError: (error, trace) {
      status = VanImageStatus.error;
      if (setStateFn != null) setStateFn!(() {});
    }));

    return StatefulBuilder(builder: (context, setState) {
      setStateFn = setState;

      Gradient? gradient = status == VanImageStatus.completed ? null : style.placeholderBackground?.gradient;
      Color? color = status == VanImageStatus.completed ? null : style.placeholderBackground?.color;
      Widget? place;

      if (status == VanImageStatus.loading) {
        if (childLoading != null) {
          place = childLoading;
          place = IconTheme(
              data: Theme.of(context).iconTheme.copyWith(
                    color: style.loadingIconColor,
                    size: style.loadingIconSize,
                  ),
              child: place!);
        } else {
          place = CupertinoActivityIndicator(color: style.loadingIconColor);
        }
      } else if (status == VanImageStatus.error) {
        if (childError != null) {
          place = childError;
          place = IconTheme(
              data: Theme.of(context).iconTheme.copyWith(
                    color: style.errorIconColor,
                    size: style.errorIconSize,
                  ),
              child: place!);
        } else {
          place = Icon(Icons.image_not_supported_outlined, color: style.errorIconColor, size: style.errorIconSize);
        }
      }

      Widget widget = Container(
        alignment: Alignment.center,
        width: style.width,
        height: style.height,
        decoration: BoxDecoration(
          color: color,
          gradient: gradient,
          image: decorationImage,
          borderRadius: borderRadius,
        ),
        child: place,
      );

      if (child != null) {
        widget = Column(children: [
          widget,
          SizedBox(width: style.width, child: child!),
        ]);
      }

      if (place != null || child != null) {
        widget = DefaultTextStyle.merge(
          style: TextStyle(color: style.placeholderTextColor, fontSize: style.placeholderFontSize),
          child: widget,
        );
      }
      return widget;
    });
  }
}
